package com.hulk.dryad.web.oauth2.service;

import cn.hutool.core.util.StrUtil;
import com.hulk.dryad.common.constant.CommonConstants;
import com.hulk.dryad.common.constant.SecurityConstants;
import com.hulk.dryad.common.constant.enums.LoginType;
import com.hulk.dryad.common.util.WebUtils;
import com.hulk.dryad.web.api.vo.CustomerLoginRespVO;
import com.hulk.dryad.web.api.vo.CustomerPwdLoginReqVO;
import com.hulk.dryad.web.api.vo.CustomerSMSLoginReqVO;
import com.hulk.dryad.web.api.vo.CustomerSocialLoginReqVO;
import com.hulk.dryad.web.oauth2.base.service.DryadUser;
import com.hulk.dryad.web.oauth2.base.service.DryadUserDetailsService;
import com.hulk.dryad.web.service.CustomerServiceImpl;
import com.hulk.dryad.web.service.OAuth2ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 用户详细信息
 *
 * @author hulk
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DryadUserDetailsServiceImpl implements DryadUserDetailsService {

	private final CustomerServiceImpl customerServiceImpl;
	private final OAuth2ServiceImpl oAuth2ServiceImpl;





	/**
	 * 用户密码登录
	 *
	 * @param username 用户名
	 * @return
	 * @throws UsernameNotFoundException
	 */
	@SneakyThrows
	@Override
	public UserDetails loadUserByUsername(String username) {


		HttpServletRequest request = WebUtils.getRequest();
		String loginType = request.getParameter(SecurityConstants.LOGIN_TYPE);
		if(!StrUtil.equals(loginType,LoginType.PWD.getType())){
			throw new UsernameNotFoundException("loginType字段错误");
		}
		String grantType = request.getParameter(SecurityConstants.GRANT_TYPE);
		UserDetails userDetails;
		if (Strings.isBlank(grantType)) {
			throw new UsernameNotFoundException("grant_type字段不能为空");
		}
		if (SecurityConstants.REFRESH_TOKEN.equals(grantType)) {
			CustomerLoginRespVO result = customerServiceImpl.refresh(username,loginType);
			userDetails = getCustomerDetails(result,request);
		} else {
			CustomerPwdLoginReqVO reqVo = new CustomerPwdLoginReqVO();
			reqVo.setLoginNo(username);
			reqVo.setLoginType(loginType);
			CustomerLoginRespVO result = customerServiceImpl.loginPostByPassword(reqVo);
			userDetails = getCustomerDetails(result,request);

		}

		return userDetails;
	}


	/**
	 * 根据验证码 登录
	 *
	 * @param mobile TYPE@CODE
	 * @return UserDetails
	 * @throws UsernameNotFoundException
	 */
	@Override
	@SneakyThrows
	public UserDetails loadUserBySMSCode(String mobile) {
		log.info("mobile:[{}] loadUserBySMSCode", mobile);

		HttpServletRequest request = WebUtils.getRequest();
		String loginType = request.getParameter(SecurityConstants.LOGIN_TYPE);
		if(!StrUtil.equals(loginType,LoginType.SMS.getType())){
			throw new UsernameNotFoundException("loginType字段错误");
		}
		String grantType = request.getParameter(SecurityConstants.GRANT_TYPE);
		UserDetails userDetails;
		if (Strings.isBlank(grantType)) {
			throw new UsernameNotFoundException("grant_type字段不能为空");
		}
		if (SecurityConstants.REFRESH_TOKEN.equals(grantType)) {
			CustomerLoginRespVO result = customerServiceImpl.refresh(mobile,loginType);
			userDetails = getCustomerDetails(result,request);
		} else {
			CustomerSMSLoginReqVO reqVo = new CustomerSMSLoginReqVO();
			reqVo.setLoginNo(mobile);
			//验证码
			String smsCode = request.getParameter("sms_code");
			reqVo.setSmsCode(smsCode);
			reqVo.setLoginType(loginType);
			CustomerLoginRespVO respDto = customerServiceImpl.loginPostBySMS(reqVo);
			userDetails = getCustomerDetails(respDto,request);
		}
		return userDetails;
	}

	/**
	 * 根据社交登录code 登录
	 *
	 * @param code TYPE@CODE
	 * @return UserDetails
	 * @throws UsernameNotFoundException
	 */
	@Override
	@SneakyThrows
	public UserDetails loadUserBySocial(String code) {
		log.info("code:[{}] loadUserBySocial", code);

		UserDetails userDetails;
		HttpServletRequest request = WebUtils.getRequest();
		String loginType = request.getParameter(SecurityConstants.LOGIN_TYPE);
		if(StrUtil.isBlank(loginType)){
			throw new UsernameNotFoundException("loginType字段不能为空");
		}
		String grantType = request.getParameter(SecurityConstants.GRANT_TYPE);

		if (Strings.isBlank(grantType)) {
			throw new UsernameNotFoundException("grant_type字段不能为空");
		}
		if (SecurityConstants.REFRESH_TOKEN.equals(grantType)) {
			CustomerLoginRespVO result = customerServiceImpl.refresh(code,loginType);
			userDetails = getCustomerDetails(result,request);
		} else {
			//social类型
			CustomerSocialLoginReqVO reqVo = new CustomerSocialLoginReqVO();
			reqVo.setSocialCode(code);
			reqVo.setLoginType(loginType);
			CustomerLoginRespVO result = oAuth2ServiceImpl.manualAuth(reqVo);
			userDetails = getCustomerDetails(result,request);
		}
		return userDetails;
	}

	/**
	 * 构建APP系统userDetails
	 *
	 * @param result 用户信息
	 * @return
	 */
	private UserDetails getCustomerDetails(CustomerLoginRespVO result,HttpServletRequest request ) {
		String tenantId = request.getHeader(CommonConstants.TENANT_ID);
		if(StrUtil.isBlank(tenantId)){
			tenantId = request.getParameter(CommonConstants.TENANT_ID);
		}
		result.setTenantId(tenantId);
		//String N_A = "N/A";
		Set<String> authSet = new HashSet<>();
		authSet.add("ALL");
		Collection<? extends GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(authSet.toArray(new String[0]));
		// 构造security用户
		String password = SecurityConstants.NOOP + result.getLoginPwd();
		//String password = SecurityConstants.BCRYPT + result.getLoginPwd();
		String operatorNo = result.getOperatorNo();
		String nickName = result.getNickName();
		Integer deptId = result.getDeptId();
		String avatar = result.getAvatar();
		tenantId  =result.getTenantId();
		DryadUser user = new DryadUser(0, deptId, avatar, nickName, tenantId, operatorNo, password, true, true, true, true, authorities);
		return user;
	}

}
